﻿//EmulationDebug.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.Testing
{
	using System;
	using System.Collections.Generic;

	using Ecng.Collections;
	using Ecng.Common;

	using StockSharp.Algo.Storages;
	using StockSharp.BusinessEntities;

	/// <summary>
	/// Вспомогательный класс для программной остановки (и последующего возобновления) работы эмулятора.
	/// </summary>
	public class EmulationDebug : Disposable
	{
		private readonly static SynchronizedDictionary<RealTimeEmulationTrader<DataFeedTrader>, EmulationDebug> _cache = new SynchronizedDictionary<RealTimeEmulationTrader<DataFeedTrader>, EmulationDebug>();

		private readonly RealTimeEmulationTrader<DataFeedTrader> _trader;

		private EmulationDebug(RealTimeEmulationTrader<DataFeedTrader> trader)
		{
			_trader = trader;
			_trader.NewOrders += OnNewOrders;
			_trader.NewMyTrades += OnNewMyTrades;
			//_trader.MarketTimeChanged += OnMarketTimeChanged;
			_trader.NewTrades += OnNewTrades;
			_trader.MarketDepthsChanged += OnMarketDepthsChanged;

			//BreakOnTime = null;
		}

		/// <summary>
		/// Приостанавливать эмуляцию при возникновении собственной сделки. По умолчанию отключено.
		/// </summary>
		public bool BreakOnNewMyTrade { get; set; }

		/// <summary>
		/// Приостанавливать эмуляцию при регистрации новой заявки. По умолчанию отключено.
		/// </summary>
		public bool BreakOnNewOrder { get; set; }

		///// <summary>
		///// Приостановить эмуляцию при достижении данного момента времени. По умолчанию отключено (значение установлено в null).
		///// </summary>
		//public DateTime? BreakOnTime { get; set; }

		/// <summary>
		/// Приостановить эмуляцию на получении новой сделки. По умолчанию отключено.
		/// </summary>
		public bool BreakOnNewTrade { get; set; }

		/// <summary>
		/// Приостановить эмуляцию на получении нового стакана. По умолчанию отключено.
		/// </summary>
		public bool BreakOnNewDepth { get; set; }

		/// <summary>
		/// Получить <see cref="EmulationDebug"/>.
		/// </summary>
		/// <param name="trader">Интерфейс шлюза-эмулятора биржи.</param>
		/// <returns>API для программной приостановки исполнения стратегии.</returns>
		public static EmulationDebug Get(RealTimeEmulationTrader<DataFeedTrader> trader)
		{
			if (trader == null)
				throw new ArgumentNullException("trader");

			return _cache.SafeAdd(trader, key => new EmulationDebug(key));
		}

		/// <summary>
		/// Приостановить исполнение эмулятора. Для возобновления необходимо вызвать <see cref="Resume"/>.
		/// </summary>
		public void Break()
		{
			if (_trader.UnderlyingTrader.State == EmulationStates.Started)
				_trader.UnderlyingTrader.Suspend();
		}

		/// <summary>
		/// Возобновить исполнение эмулятора.
		/// </summary>
		public void Resume()
		{
			if (_trader.UnderlyingTrader.State == EmulationStates.Suspended)
				_trader.UnderlyingTrader.Resume();
		}

		//private void OnMarketTimeChanged()
		//{
		//    if (BreakOnTime != null)
		//    {
		//        if (_trader.MarketTime >= BreakOnTime)
		//            Break();
		//    }
		//}

		private void OnNewMyTrades(IEnumerable<MyTrade> trades)
		{
			if (BreakOnNewMyTrade)
				Break();
		}

		private void OnNewOrders(IEnumerable<Order> orders)
		{
			if (BreakOnNewOrder)
				Break();
		}

		private void OnNewTrades(IEnumerable<Trade> trades)
		{
			if (BreakOnNewTrade)
				Break();
		}

		private void OnMarketDepthsChanged(IEnumerable<MarketDepth> depths)
		{
			if (BreakOnNewDepth)
				Break();
		}

		/// <summary>
		/// Освободить занятые ресурсы.
		/// </summary>
		protected override void DisposeManaged()
		{
			_trader.NewOrders -= OnNewOrders;
			_trader.NewMyTrades -= OnNewMyTrades;
			//_trader.MarketTimeChanged -= OnMarketTimeChanged;
			_trader.NewTrades -= OnNewTrades;
			_trader.MarketDepthsChanged -= OnMarketDepthsChanged;

			base.DisposeManaged();
		}
	}
}